﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Genuilder.Extensibility;
using Genuilder.Extensions.LinqToXsd;
using System.Runtime.Serialization;
using System.Xml.Linq;

namespace Genuilder.Extensions
{
	[DataContract]
	public class XmlToClrNamespaceMapping
	{
		/// <summary>
		/// Map a xml namespace to clr namespace
		/// </summary>
		/// <param name="xmlNs"></param>
		/// <param name="clrNs">Use place holder {{DefaultNamespace}} to use the default namespace of the project</param>
		public XmlToClrNamespaceMapping(string xmlNs, string clrNs)
		{
			XmlNamespace = xmlNs;
			ClrNamespace = clrNs;
		}
		[DataMember]
		public string XmlNamespace
		{
			get;
			set;
		}
		[DataMember]
		public string ClrNamespace
		{
			get;
			set;
		}

		internal XElement CreateNamespaceMapping(string defaultNamespace)
		{
			return new XElement(LinqToXsdExtension.LinqToXsdNs + "Namespace",
				new XAttribute("Schema", XmlNamespace),
				new XAttribute("Clr", ClrNamespace.Replace("{{DefaultNamespace}}", defaultNamespace)));
		}
	}
	[DataContract]
	public class LinqToXsdExtension : IExtension
	{
		public LinqToXsdExtension()
		{
			XmlSerializable = true;
		}
		[DataMember]
		public FileQuery Xsds
		{
			get;
			set;
		}

		[DataMember]
		public bool XmlSerializable
		{
			get;
			set;
		}

		[DataMember]
		public List<XmlToClrNamespaceMapping> NamespaceMappings
		{
			get;
			set;
		}

		#region IExtension Members

		public void Execute(ExtensionContext extensionContext)
		{
			Xsds = Xsds ?? new FileQuery().SelectInThisDirectory(true).EndWith(".xsd").ToQuery();
			var generator = new XObjectsGenerator(extensionContext);
			var xsdFiles = extensionContext.GenItems.GetByQuery(Xsds).ToList();
			if(xsdFiles.Any(x => x.Modified))
			{
				var outputFile = extensionContext.GenItems.CreateNew("LinqToXsd.g.cs");
				var configFile = CreateConfigFile(extensionContext);
				generator.GenerateXObjects(xsdFiles.Select(x => x.Name).ToArray(),  outputFile.Name,configFile, XmlSerializable);
			}
		}

		internal static readonly XNamespace LinqToXsdNs = "http://www.microsoft.com/xml/schema/linq";

		private string CreateConfigFile(ExtensionContext extension)
		{
			if(NamespaceMappings == null || NamespaceMappings.Count == 0)
				return null;
			XDocument document =
				new XDocument(
					new XElement(LinqToXsdNs + "Configuration",
						new XElement(LinqToXsdNs + "Namespaces",
							NamespaceMappings.Select(m => m.CreateNamespaceMapping(extension.ExecutionContext.ProjectInfo.RootNamespace)).ToArray()))
				);
			var config = extension.GenItems.CreateNew("LinqToXsd.xo", SourceType.None);
			document.Save(config.Name);
			return config.Name;
		}

		#endregion
	}
}
